﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using System.Xml.Linq;

namespace LotroData
{
    /// <summary>
    /// Contains specific extension classes
    /// </summary>
    public static class LotroExtensions
    {
        /// <summary>
        /// Gets the string value from the appropriate attribute.
        /// If there is no attribute specified, uses ToString()
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static string GetStringValue(this Enum value)
        {
            Type type = value.GetType();

            // Get fieldinfo for this type
            FieldInfo fieldInfo = type.GetField(value.ToString());

            // Get the stringvalue attributes
            StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
                typeof(StringValueAttribute), false) as StringValueAttribute[];

            // Return the first if there was a match.b
            return attribs.Length > 0 ? attribs[0].Value : value.ToString();
        }

        /// <summary>
        /// Determines whether the Enumeration value can be associated with LoTRO Free Characters.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>
        /// 	<c>true</c> if the attribute exists; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsFreeCharacterUsable(this Enum value)
        {
            Type type = value.GetType();

            // Get fieldinfo for this type
            FieldInfo fieldInfo = type.GetField(value.ToString());

            // Get the stringvalue attributes
            LotroFreeCharacterAttribute[] attribs = fieldInfo.GetCustomAttributes(
                typeof(LotroFreeCharacterAttribute), false) as LotroFreeCharacterAttribute[];

            // Return the first if there was a match.b
            return attribs.Any();

        }

        /// <summary>
        /// Determines whether the specified guild type is that of a Kinship.
        /// </summary>
        /// <param name="guildType">Type of the guild.</param>
        /// <returns>
        /// 	<c>true</c> if the specified guild type is a kinship; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsKinship(this LotroGuildTheme guildType)
        {
            return guildType == LotroGuildTheme.DwarfKinshipTheme ||
                guildType == LotroGuildTheme.ElfKinshipTheme ||
                guildType == LotroGuildTheme.HobbitKinshipTheme ||
                guildType == LotroGuildTheme.ManKinshipTheme ||
                guildType == LotroGuildTheme.MixedKinshipTheme;
        }

        /// <summary>
        /// Converts a <see cref="LotroCharacter"/> stat string value to an <c>int</c>.
        /// </summary>
        /// <remarks>
        /// If the value is ??, the function returns -1;
        /// If the value is N/A, the function returns -2;
        /// Otherwise, int.Parse is called.
        /// </remarks>
        /// <param name="value">The <see cref="System.String"/> value.</param>
        /// <returns>An <c>int</c>.</returns>
        public static int ToStatValue(this string value)
        {
            if (value == "??")
                return -1;
            else if (value == "N/A")
                return -2;
            else
                return int.Parse(value, System.Globalization.CultureInfo.CurrentCulture);
        }

        /// <summary>
        /// Converts an <c>int</c> to the stat string representation using the current culture.
        /// </summary>
        /// <param name="value">The <c>int</c> value.</param>
        /// <returns>A <see cref="System.String"/>.</returns>
        public static string ToStatString(this int value)
        {
            return ToStatString(value, System.Globalization.CultureInfo.CurrentCulture);
        }

        /// <summary>
        /// Converts an <c>int</c> to the stat string representation using the provider formatter
        /// </summary>
        /// <param name="value">The <c>int</c> value.</param>
        /// <param name="format">The format provider.</param>
        /// <returns>A <see cref="System.String"/>.</returns>
        public static string ToStatString(this int value, IFormatProvider format)
        {
            if (value == -1)
                return "??";
            else if (value == -2)
                return "N/A";
            else
                return value.ToString(format);
        }

        /// <summary>
        /// Parses a <see cref="System.String"/> value into a specific LotroData enumeration.
        /// </summary>
        /// <exception cref="ArgumentException">Occurs when the type parameter T is not an enumeration.</exception>
        /// <typeparam name="T">A LotroData enumeration to return.</typeparam>
        /// <param name="value">The <see cref="System.String"/> value.</param>
        /// <returns></returns>
        public static T ParseLotroEnum<T>(this string value) where T : struct
        {
            return ParseLotroEnum<T>(value, false);
        }


        /// <summary>
        /// Parses a <see cref="System.String"/> value into a specific LotroData enumeration.
        /// </summary>
        /// <exception cref="ArgumentException">Occurs when the type parameter T is not an enumeration.</exception>
        /// <typeparam name="T">A LotroData enumeration to return.</typeparam>
        /// <param name="value">The <see cref="System.String"/> value.</param>
        /// <param name="ignoreCase">if set to <c>true</c>, the case of the string value is ignored.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly",
            Justification = "No specific exception type exists for generic types. This is most relevant")]
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter",
            Justification = "This is designed behaviour, the type argument denotes the return value")]
        public static T ParseLotroEnum<T>(this string value, bool ignoreCase) where T : struct
        {
            if (!typeof(T).IsEnum) throw new ArgumentException("Generic type must be an Enumeration", "T");

            value = value.Trim();
            if (value.Length == 0) return default(T);

            var regex = new System.Text.RegularExpressions.Regex("[^a-zA-Z0-9]");
            value = regex.Replace(value, "");

            try
            {
                return (T)Enum.Parse(typeof(T), value, ignoreCase);
            }
            catch
            {
                return default(T);
            }
        }
    }
}
